package com.lagou.session;

import com.lagou.pojo.Configuration;
import com.lagou.pojo.MappedStatement;

import java.lang.reflect.Proxy;
import java.util.List;
import java.util.Map;

public class DefaultSqlSession implements SqlSession {

    private Configuration configuration;

    public DefaultSqlSession(Configuration configuration) {
        this.configuration = configuration;
    }

    @Override
    public <E> List<E> selectList(String statementId, Object... params) {
        Map<String, MappedStatement> map = configuration.getMap();
        MappedStatement mappedStatement = map.get(statementId);
        SimpleExecutor simpleExecutor = new SimpleExecutor(configuration);
        try {
            return simpleExecutor.query(configuration, mappedStatement, params);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    @Override
    public <T> T selectOne(String statementId, Object... params) {
        List<Object> objects = this.selectList(statementId, params);
        if (objects.size() == 1) {
            return (T) objects.get(0);
        } else {
            throw new RuntimeException("too many result");
        }
    }

    @Override
    public int update(String statementId, Object... params) throws Exception {
        Map<String, MappedStatement> map = configuration.getMap();
        MappedStatement mappedStatement = map.get(statementId);
        // 构造执行器
        Executor simpleExecutor = new SimpleExecutor(configuration);
        return simpleExecutor.nativeSql(mappedStatement, params);
    }

    @Override
    public int insert(String statementId, Object... params) throws Exception {
        // 都是update
        return this.update(statementId, params);
    }

    @Override
    public int delete(String statementId, Object... params) throws Exception {
        // 都是update
        return this.update(statementId, params);
    }

    @Override
    public <T> T getMapper(Class<?> clazz) {
        Object o = Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{clazz}, (proxy, method, args) -> {
            // 获取类全路径
            String className = method.getDeclaringClass().getName();
            // 获取方法名
            String methodName = method.getName();
            // statementId
            String statementId = className + "." + methodName;
            Map<String, MappedStatement> map = this.configuration.getMap();
            // 根据statementId 获取映射类
            MappedStatement mappedStatement = map.get(statementId);
            if (mappedStatement == null) {
                throw new RuntimeException("Invalid bound statement (not found): " + statementId);
            }
            // 执行
            return execute(mappedStatement, args);
        });
        return (T) o;
    }

    /**
     * 动态代理执行sql
     */
    public Object execute(MappedStatement mappedStatement, Object[] args) throws Exception {
        String statementId = mappedStatement.getId();
        String type = mappedStatement.getType();
        if(type.equals(SQLTYPE.SELECT)){
            return this.selectList(statementId,args);
        }else if(type.equals(SQLTYPE.INSERT)){
            return this.insert(statementId,args);
        }else if(type.equals(SQLTYPE.UPDATE)){
            return this.update(statementId,args);
        }else if(type.equals(SQLTYPE.DELETE)){
            return this.delete(statementId,args);
        }
        return null;
    }

    /**
     * sql类型
     */
    enum SQLTYPE{
       SELECT("select",1),UPDATE("update",2),INSERT("insert",3),DELETE("delete",4);
        private String type;
        private int index;
      private   SQLTYPE(String type, int index) {
            this.type = type;
            this.index = index;
        }
    }

}
